﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SmartMathLibrary.Statistics
{
    /// <summary>
    /// This class provides the creation of a moving average timeseries.
    /// </summary>
    [Serializable]
    public class MovingAverageCreator
    {
        /// <summary>
        /// This field holds the timeseries from which the moving average should be computed.
        /// </summary>
        private TimeSeries series;

        /// <summary>
        /// Initializes a new instance of the <see cref="MovingAverageCreator"/> class.
        /// </summary>
        /// <param name="series">The timeseries from which the moving average should be computed.</param>
        public MovingAverageCreator(TimeSeries series)
        {
            if (series == (TimeSeries) null)
            {
                throw new ArgumentNullException("series");
            }

            if (series.Data == (GeneralVector) null)
            {
                throw new ArgumentNullException("series");
            }

            this.series = series;
        }

        /// <summary>
        /// Gets or sets the timeseries from which the moving average should be computed.
        /// </summary>
        /// <value>The timeseries from which the moving average should be computed.</value>
        public TimeSeries Series
        {
            get { return this.series; }
            set { this.series = value; }
        }

        /// <summary>
        /// Creates the moving average of the specified timeseries.
        /// </summary>
        /// <param name="order">The order of the moving average to create.</param>
        /// <returns>A new timeseries, which includes the moving average data.</returns>
        public TimeSeries CreateMovingAveragedSeries(int order)
        {
            if (this.series.Data.Count < order)
            {
                throw new ArgumentException("The length of the series has to be greater the specified order.");
            }

            double movingAVG = 0;
            GeneralVector result;

            if (ExtendedMath.IsOdd(order))
            {
                result = new GeneralVector(this.series.Data.Count - (order - 1));

                for (int i = 0; i < order; i++)
                {
                    movingAVG += this.series.Data[i];
                }

                movingAVG /= order;
                result[0] = movingAVG;

                for (int i = 1; i < result.Count; i++)
                {
                    result[i] = result[i - 1] + (this.series.Data[i + order - 1] - this.series.Data[i - 1])/order;
                }
            }
            else
            {
                order++;
                result = new GeneralVector(this.series.Data.Count - ((order - 1)));

                for (int i = 0; i < order; i++)
                {
                    movingAVG += this.series.Data[i];
                }

                movingAVG /= order;
                result[0] = movingAVG;

                for (int i = 1; i < result.Count; i++)
                {
                    result[i] = result[i - 1] +
                                (this.series.Data[i + order - 1] + this.series.Data[i + order - 2] - this.series.Data[i] -
                                 this.series.Data[i - 1])/(2*(order - 1));
                }
            }

            return new TimeSeries(result);
        }
    }
}